package com.myk.game.gobangchess.rooms;

import com.myk.game.gobangchess.Room;
import com.myk.game.gobangchess.Sign;
import com.myk.game.gobangchess.constants.ColorCost;
import com.myk.game.gobangchess.signs.*;
import com.myk.game.gobangchess.utils.GridsUtils;
import com.myk.game.gobangchess.utils.Pair;

import java.util.*;
import java.util.List;

/**
 * 象夫
 * https://tieba.baidu.com/p/10146591856?frwh=index
 */
public class XiangFuChessRoom extends Room {

    private static final int BLACK_SLOT_ROW = 0;    // 黑方拘台所在行
    private static final int WHITE_SLOT_ROW = 10;    // 白方拘台所在行
    private static final int BOARD_START_ROW = 1;   // 棋盘开始行
    private static final int BOARD_END_ROW = 9;     // 盘结束行
    private static final int ARENA_START_ROW = 3;   // 擂台开始行
    private static final int ARENA_END_ROW = 7;     // 擂台结束行
    private static final int ARENA_START_COL = 2;   // 擂台开始列
    private static final int ARENA_END_COL = 6;     // 擂台结束列

    private CacheSign cacheSign; // 缓存标记
    private List<Chess> chessList; // 场上棋子集合
    private Komadai blackKomadai; // 黑方拘台
    private Komadai whiteKomadai; // 白方拘台
    private Chess choose; // 当前选中的棋子
    private Chess select; // 当前选中的俘虏
    private GroundSign dropTip; // 打入坐标提示
    private LineSign moveTip; // 移动箭头提示

    public XiangFuChessRoom(String roomName) {
        super(roomName, "      pychess2025年设计比赛冠军，设计者Eventlesstew。\n      作者原意是功夫+象棋简称象夫，实际上与象棋区别很大，有双王机制并且加入了打入元素和区域地形元素。", "象夫", GridsUtils.createEmptyGrids(11, 9), true, true);
        initChessBoardStyle();
    }

    // 初始化背景样式
    private void initChessBoardStyle() {
        List<Sign> chessboardStyle = new ArrayList<>();
        int row = curGrids.length;
        int col = curGrids[0].length;
        //将画布默认格子隐藏了
        chessboardStyle.add(new GroundSign(getIndex(0, 0), getIndex(row - 1, col - 1), ColorCost.TABLECLOTH_COLOR, ColorCost.TABLECLOTH_COLOR, 2.0f, 0, 0));
        //画棋盘背景色
        chessboardStyle.add(new GroundSign(getIndex(BOARD_START_ROW, 0), getIndex(BOARD_END_ROW, col - 1), "#FFFDCD83", "#FFFDCD83", 1.0f, 0, 0));
        // 画拘台区域背景色
        chessboardStyle.add(new GroundSign(getIndex(0, 0), getIndex(BLACK_SLOT_ROW, 6), ColorCost.GRAY_TRANSLUCENT, ColorCost.TRANSPARENT, 1.0f, 0, 0));
        chessboardStyle.add(new GroundSign(getIndex(WHITE_SLOT_ROW, 2), getIndex(WHITE_SLOT_ROW, col - 1), ColorCost.GRAY_TRANSLUCENT, ColorCost.TRANSPARENT, 1.0f, 0, 0));
        //画蓝色擂台
        List<Pair<Integer, Integer>> ringIndexes = new ArrayList<>();
        ringIndexes.add(new Pair<>(getIndex(ARENA_START_ROW, ARENA_START_COL), 4));
        ringIndexes.add(new Pair<>(getIndex(ARENA_START_ROW, ARENA_END_COL), 4));
        ringIndexes.add(new Pair<>(getIndex(ARENA_END_ROW, ARENA_END_COL), 4));
        ringIndexes.add(new Pair<>(getIndex(ARENA_END_ROW, ARENA_START_COL), 4));
        ringIndexes.add(new Pair<>(getIndex(ARENA_START_ROW, ARENA_START_COL), 4));
        chessboardStyle.add(new PathSign(ringIndexes, "#DD5476b5", "#DD5476b5", 1.0f, 0));
        //画白色准备台
        List<Pair<Integer, Integer>> prepare1Indexes = new ArrayList<>();
        prepare1Indexes.add(new Pair<>(getIndex(BOARD_START_ROW, 0), 4));
        prepare1Indexes.add(new Pair<>(getIndex(BOARD_START_ROW, col - 1), 4));
        prepare1Indexes.add(new Pair<>(getIndex(BOARD_START_ROW + 1, col - 1), 4));
        prepare1Indexes.add(new Pair<>(getIndex(BOARD_START_ROW + 1, 0), 4));
        prepare1Indexes.add(new Pair<>(getIndex(BOARD_START_ROW, 0), 4));
        chessboardStyle.add(new PathSign(prepare1Indexes, "#DDEEEEEE", "#DDEEEEEE", 1.0f, 0));
        List<Pair<Integer, Integer>> prepare2Indexes = new ArrayList<>();
        prepare2Indexes.add(new Pair<>(getIndex(BOARD_END_ROW, 0), 4));
        prepare2Indexes.add(new Pair<>(getIndex(BOARD_END_ROW, col - 1), 4));
        prepare2Indexes.add(new Pair<>(getIndex(BOARD_END_ROW - 1, col - 1), 4));
        prepare2Indexes.add(new Pair<>(getIndex(BOARD_END_ROW - 1, 0), 4));
        prepare2Indexes.add(new Pair<>(getIndex(BOARD_END_ROW, 0), 4));
        chessboardStyle.add(new PathSign(prepare2Indexes, "#CCEEEEEE", "#CCEEEEEE", 1.0f, 0));
        //绘制棋盘格子
        for (int i = BOARD_START_ROW; i <= BOARD_END_ROW; i++) {
            for (int j = 0; j < col; j++) {
                int top = 1;
                int right = 1;
                int bottom = 1;
                int left = 1;
                int leftTop = 1;
                int rightTop = 1;
                int rightBottom = 1;
                int leftBottom = 1;
                if (i == BOARD_START_ROW) {
                    top = 0;
                    leftTop = 0;
                    rightTop = 0;
                }
                if (j == col - 1) {
                    right = 0;
                    rightBottom = 0;
                    rightTop = 0;
                }
                if (i == BOARD_END_ROW) {
                    bottom = 0;
                    leftBottom = 0;
                    rightBottom = 0;
                }
                if (j == 0) {
                    left = 0;
                    leftBottom = 0;
                    leftTop = 0;
                }
                //斜线
                chessboardStyle.add(FigureSign.makeSingleFigure(getIndex(i, j), "#66888888").setCorCenLine(leftTop, rightTop, rightBottom, leftBottom));
                //直线
                chessboardStyle.add(FigureSign.makeSingleFigure(getIndex(i, j), ColorCost.BOARD_LINE).setMidCenLine(top, right, bottom, left));
            }
        }

        // 添加到缓存标记中
        cacheSign = new CacheSign(this, "background", 5, true, chessboardStyle); // *** 修改背景样式记得改这里的版本号！！！
    }

    @Override
    public CacheSign getCacheSignByName(String cacheName) {
        return cacheSign;
    }

    @Override
    public String getCoordMode() {
        return "40011100";
    }

    @Override
    public String getGameInfo() {
        // 先全部初始化
        curGrids = GridsUtils.copyGrids(originGrids);
        signList.clear();
        signList.add(cacheSign);

        // 根据chessList集合和choose对象来生成要显示到客户端的布局和标记
        if (chessList != null && chessList.size() > 0) {
            // 绘制棋子
            for (Chess chess : chessList) {
                // 棋子自身形象在内部绘制
                chess.drawSelf(this);
                // 表示方向的小箭头则在外部绘制
                if (chess.side == 1) {
                    signList.add(new TitleSign((chess.col + 0.5f) / curGrids[0].length, (chess.row + 0.785f) / curGrids.length, 0, "▼", "#FF111111", 0.1f));
                }
                else {
                    signList.add(new TitleSign((chess.col + 0.5f) / curGrids[0].length, (chess.row + 0.215f) / curGrids.length, 0, "▲", "#FFEEEEEE", 0.1f));
                }
            }

            // 绘制拘台
            if (blackKomadai != null && whiteKomadai != null) {
                blackKomadai.drawSelf(this);
                whiteKomadai.drawSelf(this);
            }

            // 绘制打入坐标框框
            if (dropTip != null) {
                signList.add(dropTip);
            }

            // 绘制主动移动箭头
            if (moveTip != null) {
                signList.add(moveTip);
            }

            // 绘制对弈时的选中棋子移动状态
            if (choose != null) {
                choose.drawCanMovedPath(this); // 绘制棋子可移动路径
            }

            // 绘制对弈时选中的俘虏可打入路径
            if (select != null) {
                select.drawCanDropPos(this); // 绘制俘虏可打入的位置
            }
        }

        return super.getGameInfo();
    }

    @Override
    public String getRuleText() {
        return "《象夫》\n" +
                "基本规则：\n" +
                "    9x9大小棋盘，中间5x5区域为擂台，双方底线两行为准备区。\n" +
                "    有双王机制，每方都有2个帅/将，可以被吃掉1个，2个将/帅都被吃掉才算输。\n" +
                "    有打入规则类似将棋，吃掉对方棋子变为己方俘虏，只不过只能打入己方底线两行的准备区。\n" +
                "棋子走法：\n" +
                "    将/帅——斜或直走1格，与国际象棋的王一致，但不能出擂台。(特殊：帅/将被吃后会变成生/徒，走法不变但是可以出擂台 )。\n" +
                "    象/相——斜或直走2格，不能越过棋子(也就是会被塞象眼)。就是象棋的相/象加入了直线的走法，于是也有了直线的象眼。\n" +
                "    馬/傌——和中国象棋的馬一致(也就是会被绊馬腿)。\n" +
                "    砲/炮——和中国象棋的炮一致，走子为直走任意格，吃子为越过一个棋子后任意格。\n" +
                "    弓/弩——走子为斜走任意格，吃子为斜着越过一个棋子后任意格。其实就是炮的斜线版本。\n" +
                "    車/俥——和中国象棋的车一致，直走任意格。\n" +
                "    道/行——斜走任意格，和国象主教一致。";
    }

    @Override
    public void resetGrids() {
        super.resetGrids();
        chessList = null;
        choose = null;
        select = null;
        dropTip = null;
        moveTip = null;
        blackKomadai = null;
        whiteKomadai = null;
    }

    @Override
    protected void onStartPrepare() {
        // 重新创建初始布局的棋子们
        chessList = new ArrayList<>();
        blackKomadai = new Komadai(1, this);
        whiteKomadai = new Komadai(2, this);

        // 黑方棋子（顶部）
        // 第1行：車(1,2)、道(1,3)、象(1,4)
        chessList.add(new Rook(1, 1, 2));
        chessList.add(new Bishop(1, 1, 3));
        chessList.add(new Elephant(1, 1, 4));

        // 第2行：砲(2,2)、弓(2,3)、马(2,4)
        chessList.add(new Cannon(1, 2, 2));
        chessList.add(new Archer(1, 2, 3));
        chessList.add(new Knight(1, 2, 4));

        // 第3行：双王（在擂台内）将(3,2)、将(3,4)
        chessList.add(new King(1, 3, 2));
        chessList.add(new King(1, 3, 4));

        // 白方棋子（底部）
        // 第7行：双王（在擂台内）帅(7,6)、帅(7,4)
        chessList.add(new King(2, 7, 6));
        chessList.add(new King(2, 7, 4));

        // 第8行：炮(8,6)、弩(8,5)、马(8,4)
        chessList.add(new Cannon(2, 8, 6));
        chessList.add(new Archer(2, 8, 5));
        chessList.add(new Knight(2, 8, 4));

        // 第9行：车(9,6)、行(9,5)、相(9,4)
        chessList.add(new Rook(2, 9, 6));
        chessList.add(new Bishop(2, 9, 5));
        chessList.add(new Elephant(2, 9, 4));

        //通知黑方先行
        noticeBlackMove();
    }

    @Override
    public void doRule(int row, int col, int value) {
        boolean isFightArea = isFightArea(row, col); //判断点击的是棋盘还是拘台
        boolean isChooseOrSelect = choose != null || select != null; //判断是否选定了要移动或打入的棋子

        //无选中等待选棋时
        if (!isChooseOrSelect) {
            if (isFightArea) {
                //选择场上棋子
                Chess chess = getChessByPos(row, col);
                if (chess != null && chess.side == value) {
                    chooseChess(chess);
                    noticeAllRefreshGameInfo();
                }
            }
            else {
                //选择己方拘台俘虏
                Chess captive = getCaptiveByPos(row, col);
                if (captive != null) {
                    selectCaptive(captive);
                    noticeAllRefreshGameInfo();
                }
            }
        }
        //有选中等待落子时
        else {
            if (isFightArea) {
                //选中场上棋子等待移动时
                if (choose != null) {
                    if (choose.isPosCanMove(row, col, this)) {
                        moveChess(row, col, choose); //移动棋子
                        checkOver(value); //检查胜负
                    }
                    else {
                        clearChooseSelect();
                        noticeAllRefreshGameInfo();
                    }
                }
                //选中拘台俘虏准备打入时
                else {
                    if (select.isPosCanDrop(row, col, this)) {
                        dropChess(row, col, select); //打入棋子
                        checkOver(value); //检查胜负
                    }
                    else {
                        clearChooseSelect();
                        noticeAllRefreshGameInfo();
                    }
                }
            }
            else {
                clearChooseSelect();
                noticeAllRefreshGameInfo();
            }
        }
    }

    /**
     * 移动棋子
     */
    private void moveChess(int row, int col, Chess chess) {
        dropTip = null;
        moveTip = new LineSign(getIndex(chess.row, chess.col), getIndex(row, col), "#AA88EE88", 1); //添加移动箭头提示
        Chess enemyChess = getChessByPos(row, col);
        if (enemyChess != null) {
            captureChess(enemyChess); //俘虏敌方棋子
        }
        chess.row = row;
        chess.col = col;
        chess.selected = false;
        choose = null;
    }

    /**
     * 捕获棋子
     */
    private void captureChess(Chess enemyChess) {
        if (enemyChess.side == 1) { //黑棋被俘虏
            chessList.remove(enemyChess);
            whiteKomadai.addChess(enemyChess);
            enemyChess.side = 2;
        }
        else { //白棋被俘虏
            chessList.remove(enemyChess);
            blackKomadai.addChess(enemyChess);
            enemyChess.side = 1;
        }
        //王被捕获会降级
        if (enemyChess instanceof King){
            ((King) enemyChess).downgrade();
        }
    }

    /**
     * 选中俘虏
     */
    private void selectCaptive(Chess captive) {
        if (select != null) select.selected = false;
        select = captive;
        select.selected = true;
    }

    /**
     * 打入棋子
     */
    private void dropChess(int row, int col, Chess captureChess) {
        moveTip = null;
        dropTip = new GroundSign(getIndex(row, col), "#00000000", "#AA88EE88", 1.0f, 1, 0); //添加打入点提示
        if (cur == 1) {
            blackKomadai.removeChess(captureChess);
        }
        else {
            whiteKomadai.removeChess(captureChess);
        }
        captureChess.side = cur;
        captureChess.row = row;
        captureChess.col = col;
        captureChess.selected = false;
        chessList.add(captureChess);
        select = null;
    }

    /**
     * 选中棋子
     */
    private void chooseChess(Chess chess) {
        if (choose != null) choose.selected = false;
        choose = chess;
        choose.selected = true;
    }

    /**
     * 取消各种选中状态
     */
    private void clearChooseSelect() {
        if (choose != null) {
            choose.selected = false;
            choose = null;
        }
        if (select != null) {
            select.selected = false;
            select = null;
        }
    }

    /**
     * 判断游戏是否结束
     */
    private void checkOver(int curIsBlack) {
        stepAdd(); //增加回合计数

        // 检查是否有一方的王全部被吃掉
        int blackKingCount = 0;
        int whiteKingCount = 0;

        for (Chess chess : chessList) {
            if (chess instanceof King && ((King) chess).isKing()) {
                if (chess.side == 1) {
                    blackKingCount++;
                }
                else {
                    whiteKingCount++;
                }
            }
        }

        // 黑方获胜条件：吃掉白方所有王，或吃掉1个王后将死剩余的王
        if (whiteKingCount == 0) {
            gameTip = "黑方吃掉白方所有王，黑方获胜！";
            doOver(1, "黑方获胜！");
            return;
        }

        // 白方获胜条件：吃掉黑方所有王，或吃掉1个王后将死剩余的王
        if (blackKingCount == 0) {
            gameTip = "白方吃掉黑方所有王，白方获胜！";
            doOver(2, "白方获胜！");
            return;
        }

        // 检查困毙（需要实现更复杂的逻辑，这里简化处理）
        // 切换行动方
        if (curIsBlack == 1) {
            gameTip = "-1";
            noticeWhiteMove();
        }
        else {
            gameTip = "-1";
            noticeBlackMove();
        }
    }

    /**
     * 判断坐标是否在对战区域
     * 棋盘对战区域是在整个9x9的二维数组中间7x7之中。
     */
    private boolean isFightArea(int row, int col) {
        return row >= BOARD_START_ROW && row <= BOARD_END_ROW && col >= 0 && col <= curGrids[0].length - 1;
    }

    /**
     * 根据坐标搜索棋子
     */
    private Chess getChessByPos(int row, int col) {
        for (Chess chess : chessList) {
            if (chess.row == row && chess.col == col) {
                return chess;
            }
        }
        return null;
    }

    /**
     * 根据坐标搜索俘虏棋子
     */
    private Chess getCaptiveByPos(int row, int col) {
        if (cur == 1) {
            return blackKomadai.getChessByPos(getIndex(row, col));
        }
        else {
            return whiteKomadai.getChessByPos(getIndex(row, col));
        }
    }

    // 拘台内部类
    private static class Komadai {
        private final int[] SLOT_INDEXES; //棋槽对应游戏网格界面的坐标
        private final String[] slotHeads; //每个棋槽的棋头排序
        private final int side; //拘台阵营，1：黑方，2：白方
        private final Map<String, List<Chess>> captiveMap; //被俘虏棋子容器

        public Komadai(int side, XiangFuChessRoom room) {
            this.side = side;
            this.slotHeads = new String[7]; // 7种棋子类型
            this.captiveMap = new HashMap<>();

            if (side == 1) {
                //黑方拘台棋槽坐标（顶部从左往右）
                SLOT_INDEXES = new int[]{
                        room.getIndex(0, 0),
                        room.getIndex(0, 1),
                        room.getIndex(0, 2),
                        room.getIndex(0, 3),
                        room.getIndex(0, 4),
                        room.getIndex(0, 5),
                        room.getIndex(0, 6),
                        room.getIndex(0, 7)
                };
            }
            else {
                //白方拘台棋槽坐标（底部从右往左）
                SLOT_INDEXES = new int[]{
                        room.getIndex(10, 8),
                        room.getIndex(10, 7),
                        room.getIndex(10, 6),
                        room.getIndex(10, 5),
                        room.getIndex(10, 4),
                        room.getIndex(10, 3),
                        room.getIndex(10, 2),
                };
            }
        }

        /**
         * 添加被俘虏的棋子
         */
        public void addChess(Chess chess) {
            String type = chess.getClass().getSimpleName(); // 使用类名作为棋子类型

            for (int i = 0; i < slotHeads.length; i++) {
                if (slotHeads[i] == null) { //按照顺序添加，遇到空位就初始添加整个头部索引和集合容器
                    slotHeads[i] = type;
                    List<Chess> chessArray = new ArrayList<>();
                    chessArray.add(chess);
                    captiveMap.put(type, chessArray);
                    break;
                }
                else if (slotHeads[i].equals(type)) { //找到自己所在的集合，添加进去
                    captiveMap.get(type).add(chess);
                    break;
                }
            }
        }

        /**
         * 移除被俘虏的棋子
         */
        public void removeChess(Chess chess) {
            String type = chess.getClass().getSimpleName();
            List<Chess> chessList = captiveMap.get(type);
            if (chessList != null) {
                chessList.remove(chess);
                if (chessList.isEmpty()) {
                    captiveMap.remove(type);
                    // 重新整理slotHeads
                    for (int i = 0; i < slotHeads.length; i++) {
                        if (type.equals(slotHeads[i])) {
                            slotHeads[i] = null;
                            // 将后面的元素前移
                            for (int j = i; j < slotHeads.length - 1; j++) {
                                slotHeads[j] = slotHeads[j + 1];
                            }
                            slotHeads[slotHeads.length - 1] = null;
                            break;
                        }
                    }
                }
            }
        }

        /**
         * 根据坐标搜索俘虏棋子
         */
        public Chess getChessByPos(int index) {
            for (int i = 0; i < SLOT_INDEXES.length; i++) {
                if (SLOT_INDEXES[i] == index && i < slotHeads.length && slotHeads[i] != null) {
                    List<Chess> chessList = captiveMap.get(slotHeads[i]);
                    if (chessList != null && !chessList.isEmpty()) {
                        return chessList.get(0); // 返回第一个棋子
                    }
                }
            }
            return null;
        }

        /**
         * 绘制拘台
         */
        public void drawSelf(XiangFuChessRoom room) {
            // 绘制拘台中的棋子
            for (int i = 0; i < slotHeads.length; i++) {
                if (slotHeads[i] != null) {
                    List<Chess> chessList = captiveMap.get(slotHeads[i]);
                    Chess indexChess = chessList.get(0); //取一个棋子作为绘制模板，添加的时候肯定会添加第一个，移除的时候棋头和chess列表都会移除
                    //给绘制模板设置属性用于绘制
                    indexChess.side = side;
                    indexChess.row = room.getRowByIndex(SLOT_INDEXES[i]);
                    indexChess.col = room.getColByIndex(SLOT_INDEXES[i]);
                    //棋子自身形象内部绘制
                    indexChess.drawSelf(room);
                    //相同类型棋子数量在外部绘制
                    if (chessList.size() > 1) {
                        if (side == 1) {
                            room.signList.add(new BadgeSign(SLOT_INDEXES[i], "" + chessList.size(), 7, indexChess.getColor(), "#00000000"));
                        }
                        else {
                            room.signList.add(new BadgeSign(SLOT_INDEXES[i], "" + chessList.size(), 1, indexChess.getColor(), "#00000000"));
                        }
                    }
                }
            }
        }
    }

    // 抽象棋子类
    private abstract static class Chess {
        public int side; // 棋子阵营，1：黑方，2：白方
        public int row; // 棋子所在行数
        public int col; // 棋子所在列数
        public boolean selected; // 是否被选中

        public Chess(int side, int row, int col) {
            this.side = side;
            this.row = row;
            this.col = col;
            this.selected = false;
        }

        /**
         * 获取棋子的名称
         */
        public abstract String getName();

        public String getColor(){
            if (side == 1) {
                return "#FF333333";
            }
            else {
                return "#FFFF3333";
            }
        }

        /**
         * 个性化移动限制算法
         */
        public abstract boolean isPosCanMove(int row, int col, XiangFuChessRoom room);

        /**
         * 获取可移动范围列表
         */
        public List<int[]> getCanMovedPos(XiangFuChessRoom room) {
            List<int[]> canMovedPosList = new ArrayList<>();
            int startRow = 1;
            int startCol = 0;
            int endRow = room.curGrids.length - 1;
            int endCol = room.curGrids[0].length;

            for (int i = startRow; i < endRow; i++) {
                for (int j = startCol; j < endCol; j++) {
                    if (isPosCanMove(i, j, room)) {
                        canMovedPosList.add(new int[]{i, j});
                    }
                }
            }
            return canMovedPosList;
        }

        /**
         * 判断是否可以打入到指定位置
         */
        public boolean isPosCanDrop(int row, int col, XiangFuChessRoom room) {
            // 检查是否满足基本打入限制
            if (!generalDropLimit(row, col, room)) {
                return false;
            }

            // 可以在这里添加特定的打入规则
            return true;
        }

        /**
         * 获取可以打入的位置
         */
        public List<int[]> getCanDropPos(XiangFuChessRoom room) {
            List<int[]> canDropPosList = new ArrayList<>();

            // 检查棋盘上的每个位置
            for (int row = 0; row < room.curGrids.length; row++) {
                for (int col = 0; col < room.curGrids[0].length; col++) {
                    // 如果该位置为空且满足打入限制
                    if (room.curGrids[row][col] == 0 && isPosCanDrop(row, col, room)) {
                        canDropPosList.add(new int[]{row, col});
                    }
                }
            }

            return canDropPosList;
        }

        /**
         * 打入限制检查
         * 1. 黑方只能打入第1行和第2行（底线两格）
         * 2. 白方只能打入第8行和第9行（底线两格）
         * 3. 不能在已有棋子的位置打入
         * 4. 王不能打入
         */
        protected boolean generalDropLimit(int row, int col, XiangFuChessRoom room) {
            // 黑方只能打入第1行和第2行
            if (this.side == 1) {
                if (row != BOARD_START_ROW && row != BOARD_START_ROW + 1) {
                    return false;
                }
            }
            // 白方只能打入第8行和第9行
            else if (this.side == 2) {
                if (row != BOARD_END_ROW - 1 && row != BOARD_END_ROW) {
                    return false;
                }
            }

            // 不能在已有棋子的位置打入
            if (room.curGrids[row][col] != 0) {
                return false;
            }

            return true;
        }

        /**
         * 个性化绘制
         */
        public void drawSelf(XiangFuChessRoom room) {
            if (side == 1) {
                room.curGrids[row][col] = selected ? 32 : 22;
                room.signList.add(new TitleSign((this.col + 0.5f) / room.curGrids[0].length, (this.row + 0.395f) / room.curGrids.length, 0, this.getName(), this.getColor(), 0.5f));
            }
            else {
                room.curGrids[row][col] = selected ? 31 : 21;
                room.signList.add(new TitleSign((this.col + 0.5f) / room.curGrids[0].length, (this.row + 0.495f) / room.curGrids.length, 0, this.getName(), this.getColor(), 0.5f));
            }
        }

        /**
         * 绘制可移动路径
         */
        public void drawCanMovedPath(XiangFuChessRoom room) {
            List<int[]> canMovedPosList = getCanMovedPos(room); // 获取该棋子可移动到的格子的坐标集合
            if (canMovedPosList.size() > 0) {
                for (int[] canMovedPos : canMovedPosList) {
                    room.signList.add(new TitleSign((canMovedPos[1] + 0.5f) / room.curGrids[0].length, (canMovedPos[0] + 0.5f) / room.curGrids.length, 0, "●", "#FF88EE88", 0.333f));
                }
            }
        }

        /**
         * 绘制可打入位置
         */
        public void drawCanDropPos(XiangFuChessRoom room) {
            List<int[]> canDropPosList = getCanDropPos(room); // 获取该棋子可打入的位置集合
            if (canDropPosList.size() > 0) {
                for (int[] canDropPos : canDropPosList) {
                    room.signList.add(new TitleSign((canDropPos[1] + 0.5f) / room.curGrids[0].length, (canDropPos[0] + 0.5f) / room.curGrids.length, 0, "●", "#FF88EE88", 0.333f));
                }
            }
        }

        /**
         * 坐标与棋子之间有其它棋子阻碍
         */
        protected boolean hasPieceInBetween(int startX, int startY, int endX, int endY, int[][] board) {
            // 检查是否在同一行
            if (startX == endX) {
                for (int i = Math.min(startY, endY) + 1; i < Math.max(startY, endY); i++) {
                    if (board[startX][i] != 0) return true;
                }
            }
            // 检查是否在同一列
            else if (startY == endY) {
                for (int i = Math.min(startX, endX) + 1; i < Math.max(startX, endX); i++) {
                    if (board[i][startY] != 0) return true;
                }
            }
            // 检查是否在同一条对角线上
            else if (Math.abs(startX - endX) == Math.abs(startY - endY)) {
                int deltaX = startX < endX ? 1 : -1;
                int deltaY = startY < endY ? 1 : -1;

                for (int x = startX + deltaX, y = startY + deltaY; x != endX && y != endY; x += deltaX, y += deltaY) {
                    if (board[x][y] != 0) return true;
                }
            }
            // 如果不在同一行、同一列或同一条对角线上，直接返回 false
            return false;
        }

        /**
         * 公共移动限制
         */
        protected boolean generalMoveLimit(int row, int col, XiangFuChessRoom room) {
            if (room.curGrids[row][col] % 10 == room.curGrids[this.row][this.col] % 10) return false; // 不能移动到已有自己棋子的地方
            return true;
        }
    }

    // 王（帅/将）
    private static class King extends Chess {

        // 是否降级
        private boolean isDowngrade;

        public King(int side, int row, int col) {
            super(side, row, col);
        }

        @Override
        public String getName() {
            if (isDowngrade){
                return side == 1 ? "生" : "徒";
            }
            else {
                return side == 1 ? "将" : "帥";
            }
        }

        /**
         * 降级
         */
        public void downgrade(){
            isDowngrade = true;
        }

        /**
         * 判断是否是王
         */
        public boolean isKing(){
            return !isDowngrade;
        }

        @Override
        public boolean isPosCanMove(int row, int col, XiangFuChessRoom room) {
            // 王只能在擂台内移动（中间5×5区域）
            if (row < ARENA_START_ROW || row > ARENA_END_ROW || col < ARENA_START_COL || col > ARENA_END_COL) {
                if (!isDowngrade){
                    return false;
                }
            }

            // 只能斜走或直走一格
            int rowDiff = Math.abs(row - this.row);
            int colDiff = Math.abs(col - this.col);
            if (rowDiff > 1 || colDiff > 1 || (rowDiff == 0 && colDiff == 0)) {
                return false;
            }

            return generalMoveLimit(row, col, room);
        }
    }

    // 车
    private static class Rook extends Chess {
        public Rook(int side, int row, int col) {
            super(side, row, col);
        }

        @Override
        public String getName() {
            return side == 1 ? "車" : "俥";
        }

        @Override
        public boolean isPosCanMove(int row, int col, XiangFuChessRoom room) {
            // 必须横竖走
            if (row != this.row && col != this.col) {
                return false;
            }

            // 不能越子
            if (hasPieceInBetween(this.row, this.col, row, col, room.curGrids)) {
                return false;
            }

            return generalMoveLimit(row, col, room);
        }
    }

    // 马
    private static class Knight extends Chess {
        public Knight(int side, int row, int col) {
            super(side, row, col);
        }

        @Override
        public String getName() {
            return side == 1 ? "馬" : "傌";
        }

        @Override
        public boolean isPosCanMove(int row, int col, XiangFuChessRoom room) {
            // 走日字
            int rowDiff = Math.abs(row - this.row);
            int colDiff = Math.abs(col - this.col);
            if (!((rowDiff == 2 && colDiff == 1) || (rowDiff == 1 && colDiff == 2))) {
                return false;
            }

            // 绊马腿检查
            int rowStep = row > this.row ? 1 : -1;
            int colStep = col > this.col ? 1 : -1;
            
            // 判断马脚位置（马前进方向的相邻格子）
            int blockRow, blockCol;
            if (rowDiff == 2 && colDiff == 1) {
                // 纵向走2格，横向走1格 - 检查纵向的相邻格子
                blockRow = this.row + rowStep;
                blockCol = this.col;
            } else {
                // 纵向走1格，横向走2格 - 检查横向的相邻格子
                blockRow = this.row;
                blockCol = this.col + colStep;
            }
            
            // 如果马脚位置有棋子，则不能移动
            if (room.curGrids[blockRow][blockCol] != 0) {
                return false;
            }

            return generalMoveLimit(row, col, room);
        }
    }

    // 炮
    private static class Cannon extends Chess {
        public Cannon(int side, int row, int col) {
            super(side, row, col);
        }

        @Override
        public String getName() {
            return side == 1 ? "砲" : "炮";
        }

        @Override
        public boolean isPosCanMove(int row, int col, XiangFuChessRoom room) {
            // 必须横竖走
            if (row != this.row && col != this.col) {
                return false;
            }

            // 检查目标位置是否有棋子
            boolean targetHasPiece = room.curGrids[row][col] != 0;

            if (targetHasPiece) {
                // 吃子时需要隔一子
                int count = 0;
                if (row == this.row) {
                    int minCol = Math.min(this.col, col);
                    int maxCol = Math.max(this.col, col);
                    for (int j = minCol + 1; j < maxCol; j++) {
                        if (room.curGrids[row][j] != 0) count++;
                    }
                }
                else {
                    int minRow = Math.min(this.row, row);
                    int maxRow = Math.max(this.row, row);
                    for (int i = minRow + 1; i < maxRow; i++) {
                        if (room.curGrids[i][col] != 0) count++;
                    }
                }
                return count == 1 && generalMoveLimit(row, col, room);
            }
            else {
                // 不吃子时不能越子
                return !hasPieceInBetween(this.row, this.col, row, col, room.curGrids) && generalMoveLimit(row, col, room);
            }
        }
    }

    // 象
    private static class Elephant extends Chess {
        public Elephant(int side, int row, int col) {
            super(side, row, col);
        }

        @Override
        public String getName() {
            return side == 1 ? "象" : "相";
        }

        @Override
        public boolean isPosCanMove(int row, int col, XiangFuChessRoom room) {
            int rowDiff = Math.abs(row - this.row);
            int colDiff = Math.abs(col - this.col);
            
            // 可以斜走2格或者直走2格
            if (!((rowDiff == 2 && colDiff == 2) || (rowDiff == 2 && colDiff == 0) || (rowDiff == 0 && colDiff == 2))) {
                return false;
            }

            // 不能越子
            if (hasPieceInBetween(this.row, this.col, row, col, room.curGrids)) {
                return false;
            }

            return generalMoveLimit(row, col, room);
        }
    }

    // 弓
    private static class Archer extends Chess {
        public Archer(int side, int row, int col) {
            super(side, row, col);
        }

        @Override
        public String getName() {
            return side == 1 ? "弓" : "弩";
        }

        @Override
        public boolean isPosCanMove(int row, int col, XiangFuChessRoom room) {
            // 必须斜走（同道一样的移动方式）
            if (Math.abs(row - this.row) != Math.abs(col - this.col)) {
                return false;
            }

            // 检查目标位置是否有棋子
            boolean targetHasPiece = room.curGrids[row][col] != 0;

            if (targetHasPiece) {
                // 吃子时需要隔一子（炮的斜线版逻辑）
                int count = 0;
                int rowStep = row > this.row ? 1 : -1;
                int colStep = col > this.col ? 1 : -1;
                
                // 从当前位置向目标位置移动，检查中间隔了几个棋子
                int r = this.row + rowStep;
                int c = this.col + colStep;
                
                // 确保不越界
                while (r >= 0 && r < room.curGrids.length && c >= 0 && c < room.curGrids[0].length && r != row && c != col) {
                    if (room.curGrids[r][c] != 0) {
                        count++;
                    }
                    r += rowStep;
                    c += colStep;
                }
                
                // 吃子时必须恰好隔一个棋子
                return count == 1 && generalMoveLimit(row, col, room);
            }
            else {
                // 不吃子时不能越子
                return !hasPieceInBetween(this.row, this.col, row, col, room.curGrids) && generalMoveLimit(row, col, room);
            }
        }
    }

    // 道
    private static class Bishop extends Chess {
        public Bishop(int side, int row, int col) {
            super(side, row, col);
        }

        @Override
        public String getName() {
            return side == 1 ? "道" : "行";
        }

        @Override
        public boolean isPosCanMove(int row, int col, XiangFuChessRoom room) {
            // 必须斜走
            if (Math.abs(row - this.row) != Math.abs(col - this.col)) {
                return false;
            }

            // 不能越子
            if (hasPieceInBetween(this.row, this.col, row, col, room.curGrids)) {
                return false;
            }

            return generalMoveLimit(row, col, room);
        }
    }

}
